package problems.nbitparity;

import java.io.File;
import java.util.Arrays;

import ec.ECFitnessEvaluator;
import ec.Solution;
import ge.BNFGrammarParser;
import ge.ExpressionEvaluator;
import ge.ProductionRule;

public class ParityFitnessEvaluator extends ECFitnessEvaluator {

	Class<Boolean> return_type = Boolean.class;

	int num_bits = 0;
	String[] parameter_names = null;
	Class<?>[] parameter_types = null;

	public ParityFitnessEvaluator(int num_bits, String grammar_file) {
		BNFGrammarParser parser = new BNFGrammarParser(new File(
				grammar_file),
				"problems.nbitparity.Symbols$");
		
		this.num_bits = num_bits;		
		parameter_names = new String[num_bits];
		parameter_types = new Class<?>[num_bits];
		ProductionRule.MAX_DEPTH = 8;
	
		for (int i = 0; i < num_bits; i++) {
			parameter_names[i] =  new String( new byte[] {(byte)(97+i)}, 0 );
			parameter_types[i] =  boolean.class;
		}
		
		//System.out.println(parser);
	}

	public double getFitness(Solution solution) {
		String code = getCode(solution);
		
		ExpressionEvaluator ee = null;
		try {
			ee = new ExpressionEvaluator(code, return_type, parameter_names,
					parameter_types);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Boolean[] inputs = new Boolean[num_bits];
		Arrays.fill(inputs, Boolean.FALSE);
		double fitness = 0;
		for (int i = 0; i < Math.pow(2, inputs.length); i++) {
			boolean carry = true;
			for (int j = num_bits - 1; j >= 0 && carry; j--) {
				if (carry) {
					carry = inputs[j].booleanValue();
					inputs[j] = !inputs[j];
				}
			}

			boolean solution_parity = false;
			try {
				solution_parity = (Boolean) ee.execute(inputs);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			int count = 0;
			for (int idx = 0; idx < inputs.length; idx++) {
				if (inputs[idx]) {
					count++;
				}
			}
			boolean real_parity = (count % 2 == 1);

			if (solution_parity != real_parity) {
				fitness -= 1;
			}

		}

		return fitness;
	}

	public double getMaxFitness() {
		return 0;
	}
}
